/*
Go的默认行为：
1.大写字母开头的变量是可导出的，也就是其它包可以读取的，是公有变量；
小写字母开头的就是不可导出的，是私有变量。
2.大写字母开头的函数也是一样，相当于class中的带public关键词的公有函数；
小写字母开头的就是有private关键词的私有函数
*/
package main

//分组声明
import (
	"errors"
	"fmt"
	"sort"
)

// iota枚举 使用enum，默认值为0或与上一个值相同
const (
	a1     = iota
	d1     //隐式说明是iota，但是只能等于上一个，不能上多个
	b1, c1 = iota, iota
	e1     = iota
)

// map的引用类型测试
func changeMap(v map[string]int) {
	v["monday"] = 999
}

func main() {
	//变量声明必须使用
	//定义多个变量，类型为"type"的变量, 未赋值初始值为0
	var v, v1 int = 0, 1
	//内置基础类型，布尔值，默认为false
	c := true
	var d bool
	//定义变量简化版, := 的赋值简短说明只适用于函数内部，函数外部必须var否则无法声明，var来定义全局变量
	v2, v3 := 2, 3
	fmt.Println(v, v1, v2, v3, c, d)
	//_（下划线）是个特殊的变量名，任何赋予它的值都会被丢弃。
	_, a := 4, 5 //4被丢弃，_相当于占位符
	fmt.Println(a)
	//常量const, 声明需要被使用
	const Pi float32 = 3.1415926
	const str string = "字符串"
	fmt.Println(Pi, str)
	//数值两种int和uint且长度相同，byte的go类型别名unit8，go直接定义的位数的类型包括：rune(int32)，int8，int16
	//int64, byte(uint8), uint32, uint64, 后面的位数是长度，不同的长度不可以加减赋值，浮点数float32和float64,
	//复数complex128（64位实数+64位虚数），complex64（32+32），i是衡量单位输出是0+ni的形式
	e := 5i
	var f complex64 = 6i
	fmt.Println(e, f)
	//go中的字符串是不可变的，不可以直接用string[0] = value去修改赋值，会报错，要转化[]byte（被转换字符串）类型去切片,
	//而且是一对一转换。go中字符串是可以直接 + 的，字符串可以切片string[0:]是可以的
	//
	s := "s1"
	s1 := []byte(s)
	s1[0] = 'c'
	s2 := string(s1)
	s3 := "asdfghjkl"
	fmt.Print(s2, s3[1:])
	//使用`  括起的字符串为Raw字符串，声明多行字符串
	many := `hello
			word`
	fmt.Print(many)
	//错误类型error，package的errors包
	err := errors.New("this is an error")
	if err != nil {
		fmt.Print(err)
	}
	//iota 打印
	fmt.Println(a1, b1, c1, d1, e1)
	//关于数组 var name[length]type, 数字默认返回0其他null，根c+和java一样不可随便改变长度
	var arr [3]int
	//arr := [], 	//数组可以切片arr[0:2]
	arr[0] = 1
	fmt.Println(arr[0], arr[2])
	//数组隐式, 使用...自动判断长度但是前提必须有值
	arr1 := [...]int{11, 12}
	//嵌套数组[[1 2][2 2]]
	arr2 := [...][2]int{[...]int{1, 2}, [...]int{2, 2}}
	fmt.Println(arr1, arr2)
	/*
		    slice类的内置方法，len()长度，cap()最大容量，append添加一个元素，copy赋值，注意slice是动态数组，就像python的list一样，生成的内存地址必须指向一个数组类型，
		    可以使用make或[]type去创建slice类型，slice与其绑定的数组指向同一内存，但是如果append扩容超出原数组长度，超出长度的slice会指向一个新的内存地址（也是一个新数组）
				append要求：
				1.append（）用来将元素添加到切片末尾并返回结果;
				2.调用append函数必须用原来的切片变量接收返回值;
				3.append追加元素，如果slice还有容量的话，就会将新的元素放在原来slice后面的剩余空间里，
				当底层数组装不下的时候，Go就会创建新的底层数组来保存这个切片，slice地址也随之改变。
				4.原数组不可以规定长度必须是slice，比如var arr [3]int就不可以append(arr)了
	*/
	//切片是引用类型，而array是值类型
	// make([]int) 使用make相当于var slice []int给了一个slice的长度和容量，直接声明是slice没有长度， make可以制造slice，hash和channel
	var slice []int
	slice = make([]int, 0)
	slice = arr[:]
	slice = append(slice, 1)
	fmt.Println(slice, cap(slice), &slice[0]) //&查看内存地址
	/*map类型数据，键值对map[key] = value, 相当于java hashmap，但是map没有顺序每次打印顺序会变（随机存储），
	通过hash绑定内存（hash bucket）,根hashmap一样key唯一，value可变；函数和切片都不能作为key；
	map是引用类型
	*/
	itsmap := make(map[string]string) //相当于var itsmap map[string]string,make只能声明不可以声明并赋值但var可以
	itsmap["monday"] = "星期一"
	var itsmap2 = map[string]int{"monday": 1, "tuesday": 2, "Wednesday": 3, "Thursday": 4}
	changeMap(itsmap2)
	fmt.Print(itsmap, itsmap2)
	//map的遍历，需要对key排序,把key放入切片下面是
	var sorted []string
	for key := range itsmap2 {
		sorted = append(sorted, key)
	}
	fmt.Printf("排序前的长度=%v\n", sorted)
	sort.Strings(sorted)
	fmt.Printf("排序前后的长度=%v\n", sorted)
	//结构体
	type course struct {
		courseTime int
		courseName string
	}
	course1 := course{
		courseTime: 300,
		courseName: "wo",
	}
	tramap := make(map[string]course)
	tramap["teacher"] = course1
	fmt.Println(tramap)
	//map切片动态改变长度
	var mapslice []map[string]interface{} //interface泛型
	mapslice = make([]map[string]interface{}, 2)
	mapslice[0] = make(map[string]interface{}, 2)
	mapslice[0]["name"] = "wo"
	mapslice[0]["age"] = 18

	mapslice[1] = make(map[string]interface{}, 2)
	mapslice[1]["name"] = "wo1"
	mapslice[1]["age"] = 28
	fmt.Println(mapslice)

}
